#ifndef __MATTE__
#define __MATTE__

#include "Lambertian.h"
#include "RGBColor.h"
#include "Material.h"
#include <vector>
#include "ShadowRay.h"
#include "ShadowTester.h"
#include <string>

namespace Engine
{
	class Matte : public Engine::Material
	{
	public:

		Matte() : ambientBrdf(new Lambertian), diffuseBrdf(new Lambertian)
		{}

		Matte(float p_kd, RGBColor p_color) : ambientBrdf(new Lambertian), diffuseBrdf(new Lambertian)
		{
			SetCd(p_color);
			SetKd(p_kd);
		}

		Matte(std::string p_materialName,float p_kd, RGBColor p_color) : ambientBrdf(new Lambertian)
		{
			
			m_materialTexture = new SolidColor(p_color);
			diffuseBrdf = new Lambertian(p_kd, m_materialTexture);
			SetCd(p_color);
			m_containsTexture = false;
			SetKd(p_kd);
			SetMaterialName(p_materialName);
		}

		Matte(std::string p_materialName, float p_kd, std::string& p_texturePath) : ambientBrdf(new Lambertian)
		{
			m_containsTexture = true;
			m_materialTexture = new ImageTexture(p_texturePath);
			diffuseBrdf = new Lambertian(p_kd, m_materialTexture);
			SetKd(p_kd);
			SetMaterialName(p_materialName);
			SetType(DIFF);
		}

		Matte(std::string p_materialName, float p_kd, std::string& p_texturePath, RGBColor& p_secondaryColor) : ambientBrdf(new Lambertian)
		{
			m_containsTexture = true;
			m_materialTexture = new ImageTexture(p_texturePath, p_secondaryColor);
			diffuseBrdf = new Lambertian(p_kd, m_materialTexture);
			SetKd(p_kd);
			SetMaterialName(p_materialName);
			SetType(DIFF);
		}

		void SetKa(float& p_kA)
		{
			m_kA = p_kA;
			ambientBrdf->SetKd(p_kA);
		}

		void SetKd(float& p_kD)
		{
			diffuseBrdf->SetKd(p_kD);
		}

		void SetCd(RGBColor& p_color)
		{
			diffuseBrdf->SetColor(p_color);
			ambientBrdf->SetColor(p_color);
		}

		RGBColor GetMatteColor()
		{
			return diffuseBrdf->GetColor();
		}


		/*sing Engine::Material::areaLightShade;
		RGBColor AreaLightShade(ShadeRec& sr)
		{
			return RGBColor(0);
		}

		using Engine::Material::PathShader;
		RGBColor PathShader(ShadeRec& sr)
		{
			return RGBColor(0);
		}*/

		using Engine::Material::Shade;
		RGBColor Shade(ShadeRec& sr, std::vector<Light*>& sceneLights, Tracer* p_tracerPtr, Light* p_ambientLight = NULL)
		{
			Point3D w0 = -sr.ray.d;
			//ShadowTester testForShadow(p_tracerPtr, sceneLights);

			RGBColor outputColor = RGBColor(0);

			if (p_ambientLight != NULL)
			{
				outputColor = ambientBrdf->rho(sr, w0) * p_ambientLight->L(sr);
			}

			int sizeLights = sceneLights.size();
			Point3D newOrigin = sr.localHitPoint + (kEpsilon * sr.GetNormal());
			for (int lightIndex = 0; lightIndex < sizeLights; lightIndex++)
			{
				Point3D wi = sceneLights[lightIndex]->GetDirection(sr);
				wi.normalize();
				float n_dot_wi = DOT(sr.normal ,wi);

				//how t odeal with area ligths
				

				if (n_dot_wi > 0)
				{
					ShadowRay shadowRay(newOrigin, wi);
					ShadeRec tempDetails;
					/*bool intersection = testForShadow.TestShadowRay(shadowRay, sceneLights[lightIndex]);
					if (!intersection)
					{*/
					if (!this->m_containsTexture)
					{
						RGBColor diffuseBrdfComponent = diffuseBrdf->f(sr, wi, w0);
						RGBColor sceneLightComponent = sceneLights[lightIndex]->L(sr)* n_dot_wi;

						RGBColor diffuseLightAddition = diffuseBrdfComponent * sceneLightComponent;
						outputColor = outputColor + diffuseLightAddition;
					}
					else
					{
						RGBColor diffuseBrdfComponent = diffuseBrdf->f(sr, wi, w0, true);
						
						RGBColor sceneLightComponent = sceneLights[lightIndex]->L(sr)* n_dot_wi;

						RGBColor diffuseLightAddition = diffuseBrdfComponent * sceneLightComponent;
						outputColor = outputColor + diffuseLightAddition;
					}

						
					//}
					//need to test for shadows
				
				}
			}

			return outputColor;
		}

	private:
		float m_kA;
		float m_kD;
		
		Lambertian *ambientBrdf;
		Lambertian *diffuseBrdf;
	};
}

#endif // !__MATTE__
